{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Generation with LLMs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LLM、またはLarge Language Models（大規模言語モデル）は、テキスト生成の鍵となる要素です。要するに、これらは大規模な事前訓練済みトランスフォーマーモデルで、与えられた入力テキストに基づいて次の単語（または、より正確にはトークン）を予測するように訓練されています。トークンを1つずつ予測するため、モデルを呼び出すだけでは新しい文を生成するために何かより精巧なことをする必要があります。自己回帰生成を行う必要があります。\n",
    "\n",
    "自己回帰生成は、推論時の手続きで、いくつかの初期入力を与えた状態で、モデルを反復的に呼び出す手法です。🤗 Transformersでは、これは[generate()](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate)メソッドによって処理され、これは生成能力を持つすべてのモデルで利用可能です。\n",
    "\n",
    "このチュートリアルでは、以下のことを示します：\n",
    "\n",
    "* LLMを使用してテキストを生成する方法\n",
    "* 一般的な落とし穴を回避する方法\n",
    "* LLMを最大限に活用するための次のステップ\n",
    "\n",
    "始める前に、必要なライブラリがすべてインストールされていることを確認してください：\n",
    "\n",
    "\n",
    "```bash\n",
    "pip install transformers bitsandbytes>=0.39.0 -q\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generate text"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[因果言語モデリング](https://huggingface.co/docs/transformers/main/ja/tasks/language_modeling)のためにトレーニングされた言語モデルは、テキストトークンのシーケンスを入力として受け取り、次のトークンの確率分布を返します。\n",
    "\n",
    "<!-- [GIF 1 -- FWD PASS] -->\n",
    "<figure class=\"image table text-center m-0 w-full\">\n",
    "    <video\n",
    "        style=\"max-width: 90%; margin: auto;\"\n",
    "        autoplay loop muted playsinline\n",
    "        src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/assisted-generation/gif_1_1080p.mov\"\n",
    "    ></video>\n",
    "    <figcaption>\"Forward pass of an LLM\"</figcaption>\n",
    "</figure>\n",
    "\n",
    "\n",
    "LLM（Language Model）による自己回帰生成の重要な側面の1つは、この確率分布から次のトークンを選択する方法です。このステップでは、次のイテレーションのためのトークンが得られる限り、何でも可能です。これは、確率分布から最も可能性の高いトークンを選択するだけのシンプルな方法から、結果の分布からサンプリングする前に数々の変換を適用するほど複雑な方法まで、あらゆる方法が考えられます。\n",
    "\n",
    "\n",
    "<!-- [GIF 2 -- TEXT GENERATION] -->\n",
    "<figure class=\"image table text-center m-0 w-full\">\n",
    "    <video\n",
    "        style=\"max-width: 90%; margin: auto;\"\n",
    "        autoplay loop muted playsinline\n",
    "        src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/assisted-generation/gif_2_1080p.mov\"\n",
    "    ></video>\n",
    "    <figcaption>\"Autoregressive generation iteratively selects the next token from a probability distribution to generate text\"</figcaption>\n",
    "</figure>\n",
    "\n",
    "上記のプロセスは、ある停止条件が満たされるまで反復的に繰り返されます。理想的には、停止条件はモデルによって指示され、モデルは終了シーケンス（`EOS`）トークンを出力するタイミングを学習すべきです。これがそうでない場合、生成はあらかじめ定義された最大長に達したときに停止します。\n",
    "\n",
    "トークン選択ステップと停止条件を適切に設定することは、モデルがタスクで期待どおりに振る舞うために重要です。それが、各モデルに関連付けられた [GenerationConfig](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationConfig) ファイルがある理由であり、これには優れたデフォルトの生成パラメータ化が含まれ、モデルと一緒に読み込まれます。\n",
    "\n",
    "コードについて話しましょう！\n",
    "\n",
    "<Tip>\n",
    "\n",
    "基本的なLLMの使用に興味がある場合、高レベルの [`Pipeline`](https://huggingface.co/docs/transformers/main/ja/pipeline_tutorial) インターフェースが良い出発点です。ただし、LLMはしばしば量子化やトークン選択ステップの細かい制御などの高度な機能が必要であり、これは [generate()](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) を介して最良に行われます。LLMとの自己回帰生成はリソースが多く必要であり、適切なスループットのためにGPUで実行する必要があります。\n",
    "\n",
    "</Tip>\n",
    "\n",
    "<!-- TODO: llama 2（またはより新しい一般的なベースライン）が利用可能になったら、例を更新する -->\n",
    "まず、モデルを読み込む必要があります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import AutoModelForCausalLM, BitsAndBytesConfig\n",
    "\n",
    "model = AutoModelForCausalLM.from_pretrained(\n",
    "    \"openlm-research/open_llama_7b\", device_map=\"auto\", quantization_config=BitsAndBytesConfig(load_in_4bit=True)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`from_pretrained` 呼び出しで2つのフラグがあることに注意してください：\n",
    "\n",
    "- `device_map` はモデルをあなたのGPUに移動させます\n",
    "- `load_in_4bit` は[4ビットの動的量子化](https://huggingface.co/docs/transformers/main/ja/main_classes/quantization)を適用してリソース要件を大幅に削減します\n",
    "\n",
    "モデルを初期化する他の方法もありますが、これはLLMを始めるための良い基準です。\n",
    "\n",
    "次に、[トークナイザ](https://huggingface.co/docs/transformers/main/ja/tokenizer_summary)を使用してテキスト入力を前処理する必要があります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import AutoTokenizer\n",
    "\n",
    "tokenizer = AutoTokenizer.from_pretrained(\"openlm-research/open_llama_7b\")\n",
    "model_inputs = tokenizer([\"A list of colors: red, blue\"], return_tensors=\"pt\").to(model.device)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`model_inputs` 変数は、トークン化されたテキスト入力とアテンションマスクを保持しています。 [generate()](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) は、アテンションマスクが渡されていない場合でも、最善の努力をしてそれを推測しようとしますが、できる限り渡すことをお勧めします。最適な結果を得るためです。\n",
    "\n",
    "最後に、[generate()](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate) メソッドを呼び出して生成されたトークンを取得し、それを表示する前にテキストに変換する必要があります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'A list of colors: red, blue, green, yellow, black, white, and brown'"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "generated_ids = model.generate(**model_inputs)\n",
    "tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "これで完了です！わずかなコード行数で、LLM（Large Language Model）のパワーを活用できます。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Common pitfalls"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[生成戦略](https://huggingface.co/docs/transformers/main/ja/generation_strategies)はたくさんあり、デフォルトの値があなたのユースケースに適していないことがあります。出力が期待通りでない場合、最も一般的な落とし穴とその回避方法のリストを作成しました。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig\n",
    "\n",
    "tokenizer = AutoTokenizer.from_pretrained(\"openlm-research/open_llama_7b\")\n",
    "tokenizer.pad_token = tokenizer.eos_token  # Llama has no pad token by default\n",
    "model = AutoModelForCausalLM.from_pretrained(\n",
    "    \"openlm-research/open_llama_7b\", device_map=\"auto\", quantization_config=BitsAndBytesConfig(load_in_4bit=True)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Generated output is too short/long"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[GenerationConfig](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationConfig) ファイルで指定されていない場合、`generate` はデフォルトで最大で 20 トークンまで返します。我々は `generate` コールで `max_new_tokens` を手動で設定することを強くお勧めします。これにより、返される新しいトークンの最大数を制御できます。LLM（正確には、[デコーダー専用モデル](https://huggingface.co/learn/nlp-course/chapter1/6?fw=pt)）も出力の一部として入力プロンプトを返すことに注意してください。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'A sequence of numbers: 1, 2, 3, 4, 5'"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model_inputs = tokenizer([\"A sequence of numbers: 1, 2\"], return_tensors=\"pt\").to(model.device)\n",
    "\n",
    "# By default, the output will contain up to 20 tokens\n",
    "generated_ids = model.generate(**model_inputs)\n",
    "tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Setting `max_new_tokens` allows you to control the maximum length\n",
    "generated_ids = model.generate(**model_inputs, max_new_tokens=50)\n",
    "tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Incorrect generation mode"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "デフォルトでは、 [GenerationConfig](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationConfig) ファイルで指定されていない限り、`generate` は各イテレーションで最も可能性の高いトークンを選択します（貪欲デコーディング）。タスクに応じて、これは望ましくないことがあります。チャットボットやエッセイのような創造的なタスクでは、サンプリングが有益です。一方、音声の転写や翻訳のような入力に基づくタスクでは、貪欲デコーディングが有益です。`do_sample=True` でサンプリングを有効にできます。このトピックについての詳細は、この[ブログポスト](https://huggingface.co/blog/how-to-generate)で学ぶことができます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'I am a cat. I am a cat. I am a cat. I am a cat'"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Set seed or reproducibility -- you don't need this unless you want full reproducibility\n",
    "from transformers import set_seed\n",
    "set_seed(0)\n",
    "\n",
    "model_inputs = tokenizer([\"I am a cat.\"], return_tensors=\"pt\").to(model.device)\n",
    "\n",
    "# LLM + greedy decoding = repetitive, boring output\n",
    "generated_ids = model.generate(**model_inputs)\n",
    "tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'I am a cat.\\nI just need to be. I am always.\\nEvery time'"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# With sampling, the output becomes more creative!\n",
    "generated_ids = model.generate(**model_inputs, do_sample=True)\n",
    "tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Wrong padding side"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LLM（Large Language Models）は[デコーダー専用](https://huggingface.co/learn/nlp-course/chapter1/6?fw=pt)のアーキテクチャであり、入力プロンプトを繰り返し処理することを意味します。入力が同じ長さでない場合、それらをパディングする必要があります。LLMはパッドトークンからの続きを学習していないため、入力は左パディングする必要があります。また、生成に対して注目マスクを渡し忘れないようにしてください！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# The tokenizer initialized above has right-padding active by default: the 1st sequence,\n",
    "# which is shorter, has padding on the right side. Generation fails.\n",
    "model_inputs = tokenizer(\n",
    "    [\"1, 2, 3\", \"A, B, C, D, E\"], padding=True, return_tensors=\"pt\"\n",
    ").to(model.device)\n",
    "generated_ids = model.generate(**model_inputs)\n",
    "tokenizer.batch_decode(generated_ids[0], skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1, 2, 3, 4, 5, 6,'"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# With left-padding, it works as expected!\n",
    "tokenizer = AutoTokenizer.from_pretrained(\"openlm-research/open_llama_7b\", padding_side=\"left\")\n",
    "tokenizer.pad_token = tokenizer.eos_token  # Llama has no pad token by default\n",
    "model_inputs = tokenizer(\n",
    "    [\"1, 2, 3\", \"A, B, C, D, E\"], padding=True, return_tensors=\"pt\"\n",
    ").to(model.device)\n",
    "generated_ids = model.generate(**model_inputs)\n",
    "tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Further resources"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "オートリグレッシブ生成プロセスは比較的簡単ですが、LLMを最大限に活用することは多くの要素が絡むため、挑戦的な試みとなります。LLMの使用と理解をさらに深めるための次のステップについては以下のリソースをご覧ください。\n",
    "\n",
    "<!-- TODO: 新しいガイドで完了 -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Advanced generate usage"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. [ガイド](https://huggingface.co/docs/transformers/main/ja/generation_strategies)：異なる生成方法を制御する方法、生成構成ファイルの設定方法、出力のストリーミング方法についてのガイド;\n",
    "2. [GenerationConfig](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationConfig)、[generate()](https://huggingface.co/docs/transformers/main/ja/main_classes/text_generation#transformers.GenerationMixin.generate)、および[生成関連クラス](https://huggingface.co/docs/transformers/main/ja/internal/generation_utils)に関するAPIリファレンス。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### LLM leaderboards"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. [Open LLM リーダーボード](https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard)：オープンソースモデルの品質に焦点を当てたリーダーボード;\n",
    "2. [Open LLM-Perf リーダーボード](https://huggingface.co/spaces/optimum/llm-perf-leaderboard)：LLMのスループットに焦点を当てたリーダーボード。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Latency and throughput"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. [ガイド](https://huggingface.co/docs/transformers/main/ja/main_classes/quantization)：ダイナミッククオンタイズに関するガイド。これによりメモリ要件を劇的に削減する方法が示されています。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Related libraries"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. [`text-generation-inference`](https://github.com/huggingface/text-generation-inference)：LLM用の本番向けサーバー;\n",
    "2. [`optimum`](https://github.com/huggingface/optimum)：特定のハードウェアデバイス向けに最適化された🤗 Transformersの拡張。"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 4
}
